package com.sisgh.jefdv1.cmd.command;

import com.sisgh.jefdv1.core.exec.Executor;
import com.sisgh.jefdv1.exception.cmd.InvalidCommandException;
import com.sisgh.jefdv1.exception.cmd.arg.InvalidArgumentException;
import com.sisgh.jefdv1.util.StringUtils;

import java.util.ArrayList;
import java.util.List;

public abstract class AbstractCommand implements Command {

    private static final char SPACE = ' ';

    // 命令分割器
    private List<String> splitArgs(String args) {
        if (StringUtils.isNullOrEmpty(args)) {
            return List.of();
        }

        List<String> parts = new ArrayList<>();

        StringBuilder p;

        for (int i = 0; i < args.length(); ) {
            p = new StringBuilder();
            while (i < args.length() && !Character.isWhitespace(args.charAt(i))) {
                p.append(args.charAt(i));
                ++i;
            }
            parts.add(p.toString());

            while (i < args.length() && Character.isWhitespace(args.charAt(i))) {
                ++i;
            }
        }

        return parts;
    }

    // 由子类实现的参数处理逻辑
    protected abstract void processArgs(List<String> parts) throws InvalidArgumentException;

    // 获取子类实现的命令
    protected abstract String getCmd();

    // 处理命令
    protected String getArgs(String cmd) {
        int start = getCmd().length() + 1;
        while (start < cmd.length() && Character.isWhitespace(cmd.charAt(start))) {
            ++start;
        }

        if (start >= cmd.length()) {
            return null;
        }

        return cmd.substring(start);
    }

    protected String getCmdFromInput(String cmd) {
        int space = cmd.indexOf(SPACE);
        if (space == -1) {
            return cmd.toLowerCase();
        } else {
            return cmd.substring(0, space).toLowerCase();
        }
    }

    @Override
    public void resolve(String cmd) throws InvalidCommandException {
        if (StringUtils.isEmptyOrWhitespaceOnly(cmd) || !matches(cmd)) {
            throw new InvalidCommandException("错误的命令：" + cmd);
        }

        List<String> parts = splitArgs(getArgs(cmd));
        processArgs(parts);
    }

    @Override
    public boolean matches(String cmd) {
        String actualCmd = getCmd();
        if (cmd.length() < actualCmd.length()) {
            return false;
        }

        cmd = getCmdFromInput(cmd);
        if (cmd.length() < actualCmd.length()) {
            return false;
        }

        return actualCmd.equalsIgnoreCase(cmd.substring(0, actualCmd.length()));
    }
}
